﻿using BacklogParser.Models;
using BacklogParser.Models.Procedural;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace BacklogParser.Parsers
{
    public static class DocumentParser
    {
        public static RegisterDocument ParseDocument(XElement el)
        {
            var bibliographicData = el.Descendants(Constants.Epo + "bibliographic-data").FirstOrDefault();
            var proceduralData = el.Descendants(Constants.Epo + "procedural-data").ToList();
            var eventsData = el.Descendants(Constants.Epo + "events-data").ToList();

            var result = new RegisterDocument
            {
                DocumentId = bibliographicData.Attribute("id").Value,
            };

            BibliographicDataParse(result, bibliographicData);
            ProceduralDataParse(result, proceduralData);
            EventDataParse(result, eventsData);

            return result;
        }

        private static void BibliographicDataParse(RegisterDocument document, XElement bibliographic)
        {
            var pubReference = bibliographic.Descendants(Constants.Epo + "publication-reference").First().Descendants(Constants.Epo + "document-id").First();
            document.DocumentNumber = pubReference.Descendants(Constants.Epo + "doc-number").First().Value;
            document.Publn_Kind = pubReference.Descendants(Constants.Epo + "kind").First().Value;
            document.Publn_Date = pubReference.Descendants(Constants.Epo + "date").First().Value;
            document.Publn_Country = pubReference.Descendants(Constants.Epo + "country").First().Value;

            var parties = bibliographic.Descendants(Constants.Epo + "parties").First();

            ParseParties(document, parties);

            var priorityClaim = bibliographic.Descendants(Constants.Epo + "priority-claims").FirstOrDefault();
            if (priorityClaim != null)
            {
                document.PriorityClaims = PriorityClaimParser.Parse(priorityClaim);
            }

            var classificationsIpcr = bibliographic.Descendants(Constants.Epo + "classifications-ipcr").FirstOrDefault();
            if (classificationsIpcr != null)
            {
                document.ClassificationsIpcr = ClassificationIpcrParser.Parse(classificationsIpcr);
            }

            var applicationReference = bibliographic.Descendants(Constants.Epo + "application-reference").First();
            document.ApplicationReferences = ApplicationReferenceParser.Parse(applicationReference);

            var publicationReference = bibliographic.Descendants(Constants.Epo + "publication-reference").First();
            document.PublicationReferences = PublicationReferenceParser.Parse(publicationReference);


            var languageOfFiling = bibliographic.Descendants(Constants.Epo + "language-of-filing").ToList().Select(x => x.Value);
            document.LanguageOfFiling = languageOfFiling.Count() > 0 ? string.Join(" ", languageOfFiling) : "";

            var designationOfState = bibliographic.Descendants(Constants.Epo + "designation-of-states").ToList();
            document.DesignationOfStates = DesignationOfStateParser.Parse(designationOfState);
            try
            {
                var titles = bibliographic.Descendants(Constants.Epo + "invention-title").ToList();
                document.InventionTitles = titles.Select(x => new InventionTitle { Language = x.Attribute("lang").Value, Title = x.Value }).ToList();
            }
            catch
            {
                Console.WriteLine("titles parse error");
            }

            try
            {
                var licences = bibliographic.Descendants(Constants.Epo + "licensee-data").ToList();
                document.Licences = LicenseDataParser.Parse(licences);
            }
            catch
            {
                Console.WriteLine("Licensee parse error");
            }


            var termOfGrants = bibliographic.Descendants(Constants.Epo + "term-of-grant").ToList();
            document.TermsOfGrant = TermOfGrantParser.Parse(termOfGrants);

            var datesRightsEffective = bibliographic.Descendants(Constants.Epo + "dates-rights-effective").FirstOrDefault();

            if (datesRightsEffective != null)
            {
                document.DatesRightsEffective = DatesRightsEffectiveParser.Parse(datesRightsEffective);
            }

            var citationReferences = bibliographic.Descendants(Constants.Epo + "references-cited").ToList();
            document.CitationReferences = CitationReferencesParser.Parse(citationReferences);

            var relatedDocument = bibliographic.Descendants(Constants.Epo + "related-documents").FirstOrDefault();
            if (relatedDocument != null)
            {
                document.RelatedDocument = RelatedDocumentParse.Parse(relatedDocument);
            }

            var bioDeposit = bibliographic.Descendants(Constants.Epo + "bio-deposit").ToList();
            foreach (var item in bioDeposit)
            {
                var address = string.Join(", ", item.Descendants(Constants.Epo + "address").Select(x => x.Value));
                var dtext = string.Join(", ", item.Descendants(Constants.Epo + "dtext").Select(x => x.Value));
                var accno = string.Join(", ", item.Descendants(Constants.Epo + "bio-accno").Select(x => x.Value));
                document.BioDeposit.Add(new BioDeposit { Address = address, BioAccno = accno, Dtext = dtext });
            }

            var dateApplicationRefused = bibliographic.Descendants(Constants.Epo + "date-application-refused").Select(x => x.Value);
            document.DateApplicationRefused = string.Join(", ", dateApplicationRefused);

            var dateApplicationReestablished = bibliographic.Descendants(Constants.Epo + "date-rights-reestablished").Select(x => x.Value);
            document.DateApplicationReestablished = string.Join(", ", dateApplicationReestablished);

            var dateApplicationWithdrawnByApplicant = bibliographic.Descendants(Constants.Epo + "date-application-withdrawn-by-applicant").Select(x => x.Value);
            document.DateApplicationWithdrawnByApplicant = string.Join(", ", dateApplicationWithdrawnByApplicant);

            var dateApplicationDeemedWithdrawn = bibliographic.Descendants(Constants.Epo + "date-application-deemed-withdrawn").Select(x => x.Value);
            document.DateApplicationDeemedWithdrawn = string.Join(", ", dateApplicationDeemedWithdrawn);

            var dateOfRevocation = bibliographic.Descendants(Constants.Epo + "date-of-revocation").Select(x => x.Value);
            document.DateOfRevocation = string.Join(", ", dateOfRevocation);

            var officeSpecificData = bibliographic.Descendants(Constants.Epo + "office-specific-bib-data").ToList();
            document.OfficeSpecificBibData = OfficeSpecificBibDataParser.Parse(officeSpecificData);


            var opposition = bibliographic.Descendants(Constants.Epo + "opposition-data").ToList();
            var oppositionData = OppositionDataParser.Parse(opposition);

            document.OppositionData = oppositionData;

            var textElems = bibliographic.Elements(Constants.Epo + "text").ToList();

            var textTitles = new List<Title>();

            foreach (var item in textElems)
            {
                textTitles.Add(new Title { Lang = item.Attribute("lang").Value, Text = item.Value });
            }

            document.Miscellaneous = textTitles;

            var searchReportInfo = bibliographic.Descendants(Constants.Epo + "search-reports-information").FirstOrDefault();
            if (searchReportInfo != null)
            {
                var searchReport = SearchReportParser.Parse(searchReportInfo);
                document.SearchReport = searchReport;
            }

        }

        private static void ParseParties(RegisterDocument document, XElement parties)
        {
            document.Applicants = ApplicantParser.Parse(parties);
            document.Inventors = InventorParser.Parse(parties);
            document.Agents = AgentParser.Parse(parties);
        }

        private static void ProceduralDataParse(RegisterDocument document, List<XElement> procedural)
        {
            var proceduralData = new List<ProceduralData>();
            foreach (var item in procedural)
            {
                var affectedStates = item.Descendants(Constants.Epo + "procedural-step-affected-states").FirstOrDefault();
                string affectedCountries = "";
                if (affectedStates != null)
                {
                    var countries = affectedStates.Descendants(Constants.Epo + "country").ToList().Select(x => x.Value);
                    affectedCountries = string.Join(", ", countries);
                }

                var timeLimitNode = item.Descendants(Constants.Epo + "time-limit").FirstOrDefault();
                string timeLimit = "";
                if (timeLimitNode != null)
                    timeLimit = timeLimitNode.Value;

                var gazzeteReference = item.Descendants(Constants.Epo + "gazette-reference").FirstOrDefault();

                string gazzeteNum = "";
                string gazzeteDate = "";
                string gazzeteText = "";

                if (gazzeteReference != null)
                {
                    gazzeteNum = gazzeteReference.Descendants(Constants.Epo + "gazette-num").First().Value;
                    gazzeteDate = gazzeteReference.Descendants(Constants.Epo + "date").First().Value;
                    var gazzeteTextNode = gazzeteReference.Descendants(Constants.Epo + "text").FirstOrDefault();
                    if (gazzeteTextNode != null)
                        gazzeteText = gazzeteTextNode.Value;
                }
                var result = new ProceduralData
                {
                    doc_id = document.DocumentId,
                    step_code = item.Descendants(Constants.Epo + "procedural-step-code").First().Value,
                    step_text = item.Descendants(Constants.Epo + "procedural-step-text").ToList().Select(x => new StepText(x, document.DocumentId)).ToList(),
                    step_date = item.Descendants(Constants.Epo + "procedural-step-date").ToList().Select(x => new StepDate(x, document.DocumentId)).ToList(),
                    step_result = item.Descendants(Constants.Epo + "procedural-step-result").ToList().Select(x => new StepResult(x, document.DocumentId)).ToList(),
                    affected_states = affectedCountries,
                    time_limit = timeLimit,

                    gazzete_num = gazzeteNum,
                    gazzete_date = gazzeteDate,
                    gazzete_text = gazzeteText
                };

                proceduralData.Add(result);
            }

            document.ProceduralData = proceduralData;
        }

        private static void EventDataParse(RegisterDocument document, List<XElement> events)
        {
            var res = EventsDataParser.Parse(events, document.DocumentId);

            document.EventData = res;
        }
    }
}
